from django.db import models, transaction
from django.core.cache import cache
from django.db.models import F
from django.utils import timezone
from datetime import timedelta
import random

class SMSVerification(models.Model):
    """优化后的短信验证记录模型"""
    PHONE_CHANGE = 'change'
    LOGIN_VERIFY = 'login'
    PURPOSE_CHOICES = [
        (PHONE_CHANGE, '更换手机号'),
        (LOGIN_VERIFY, '登录验证'),
    ]
    
    phone = models.CharField(max_length=11, db_index=True)
    purpose = models.CharField(max_length=20, choices=PURPOSE_CHOICES)
    code = models.CharField(max_length=6)
    session_key = models.CharField(max_length=40)
    user = models.ForeignKey(
        'User', 
        on_delete=models.CASCADE, 
        null=True, 
        blank=True,
        related_name='sms_verifications'
    )
    is_used = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    expires_at = models.DateTimeField()
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        indexes = [
            models.Index(fields=['phone', 'purpose', 'session_key']),
            models.Index(fields=['user', 'is_used']),
        ]
        verbose_name = '短信验证码'
        ordering = ['-created_at']
        
    @classmethod
    def create_record(cls, phone, purpose, request):
        """创建验证记录"""
        # 添加频率限制检查（可在视图层实现更完善的限制）
        recent_count = cls.objects.filter(
            phone=phone,
            created_at__gt=timezone.now()-timedelta(minutes=1)
        ).count()
        if recent_count >= 1:
            raise ValueError("操作过于频繁，请稍后再试")
        
        code = ''.join([str(random.randint(0, 9)) for _ in range(6)])
        expires = timezone.now() + timedelta(minutes=5)
        
        session_key = (
            str(request.user.id) if request.user.is_authenticated 
            else f"{request.META.get('REMOTE_ADDR')}_{request.META.get('HTTP_USER_AGENT','')[:30]}"
        )
        
        return cls.objects.create(
            phone=phone,
            purpose=purpose,
            code=code,
            session_key=session_key,
            expires_at=expires,
            user=request.user if request.user.is_authenticated else None
        )
    
    @classmethod
    @transaction.atomic
    def verify_and_update_phone(cls, phone, code, purpose, request):
        """验证并更新手机号（事务保护）"""
        now = timezone.now()
        verification = cls.objects.select_for_update().filter(
            phone=phone,
            code=code,
            purpose=purpose,
            is_used=False,
            expires_at__gt=now,
            session_key=(
                str(request.user.id) if request.user.is_authenticated 
                else f"{request.META.get('REMOTE_ADDR')}_{request.META.get('HTTP_USER_AGENT','')[:30]}"
            )
        ).first()
        
        if not verification:
            return False
        
        verification.is_used = True
        verification.save()
        
        if request.user.is_authenticated:
            user = request.user
            user.phone = phone
            user.save()
            
            # 创建审计日志
            PhoneChangeAuditLog.objects.create(
                user=user,
                old_phone=user.phone,
                new_phone=phone,
                verification=verification
            )
            return True
        
        return False


class PhoneChangeAuditLog(models.Model):
    """手机号变更审计日志"""
    user = models.ForeignKey(
        'User', 
        on_delete=models.CASCADE,
        related_name='phone_change_logs'
    )
    old_phone = models.CharField(max_length=20)
    new_phone = models.CharField(max_length=20)
    verification = models.OneToOneField(
        SMSVerification,
        on_delete=models.SET_NULL,
        null=True,
        blank=True
    )
    changed_at = models.DateTimeField(auto_now_add=True)
    ip_address = models.GenericIPAddressField(null=True, blank=True)
    
    class Meta:
        verbose_name = '手机号变更日志'
        verbose_name_plural = verbose_name
        ordering = ['-changed_at']